/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#include "ak_types.h"
#include "ak_queue.h"
#include "ak_gears.h"
#include "ak_xml2.h"
#include <libxml/tree.h>
#include <libxml/xmlreader.h>
#include <libxml/xpath.h>

static 	int 	_gTraceLvl_Xml2Gen = TRACELVL_DEBUG;

/* ---------------------------------------------------------------------------
** Xml2 Reader Generator :
*/

#define _SXML_MAX_ATTR 		64
#define _SXML_MAX_CHILD		64
#define _SXML_MAX_STR 		128
#define _SXML_MAX_DESC 		2048

typedef struct{
	_t_bnode 		node;
	char 			name[_SXML_MAX_STR];
}_t_xml_attr_node;

typedef struct{
	_t_bnode 		node;
	int 			depth;
	/* Name */
	char 			name[_SXML_MAX_STR];	
	
	/* Attribute */
	_t_blist		attr;	

	/* Children */
	_t_blist		child;
}_t_xml_desc_node;


static 	_t_xml_attr_node * 	_SXml2_AttrNode_Alloc(char * pName)
{
	int 	len;
	_t_xml_attr_node * pNode;

	pNode = NULL;
	if(pName){
		len = SYS_STRLEN(pName);
		if((len > 0) && (len < _SXML_MAX_STR)){
			pNode = SYS_MALLOC(sizeof(_t_xml_attr_node));
			if(pNode){
				SYS_MEMCPY(pNode->name, pName, len);
				pNode->name[len] = 0;
			}
		}
	}

	return pNode;
}

static 	int 	_SXml2_AttrNode_Free(_t_xml_attr_node * pNode)
{
	if(pNode){
		SYS_FREE(pNode);
		return 0;
	}

	return -1;
}

static 	_t_xml_desc_node * 	_SXml2_DescNode_Alloc(char * pName)
{
	int 	len;
	_t_xml_desc_node * pNode;

	pNode = NULL;
	if(pName){
		len = SYS_STRLEN(pName);
		if((len > 0) && (len < _SXML_MAX_STR)){
			pNode = SYS_MALLOC(sizeof(_t_xml_desc_node));
			if(pNode){
				SYS_MEMCPY(pNode->name, pName, len);
				pNode->name[len] = 0;
				/* Init */
				BLIST_INIT(&(pNode->attr));
				BLIST_INIT(&(pNode->child));
			}
		}
	}

	return pNode;
}

static 	int 	_SXml2_DescNode_Free(_t_xml_desc_node * pNode)
{
	_t_xml_attr_node * pAttr;
	_t_xml_desc_node * pChild;
	if(pNode){
		/* Free the Child */
		while((pChild = (_t_xml_desc_node *)BLST_GET(&(pNode->child)))){
			_SXml2_DescNode_Free(pChild);
		}
		/* Free the Attr */
		while((pAttr = (_t_xml_attr_node *)BLST_GET(&(pNode->attr)))){
			_SXml2_AttrNode_Free(pAttr);
		}

		SYS_FREE(pNode);
		return 0;
	}

	return -1;
}

static 	_t_xml_attr_node * 	_SXml2_DescNode_FindAttr(_t_xml_desc_node * pNode, char * pName)
{
	int i, count;
	_t_blist 		 * pQue;
	_t_xml_attr_node * pAttr;
	if(pNode && pName){
		pQue = &(pNode->attr);
		count = pQue->count;
		pAttr = (_t_xml_attr_node *)(pQue->head);
		for(i=0; i<count; i++, pAttr = (_t_xml_attr_node*)(pAttr->node.next)){
			if(SYS_STRCMP(pAttr->name, pName) == 0){
				return pAttr;
			}
		}
	}

	return NULL;
}

static 	_t_xml_desc_node * 	_SXml2_DescNode_FindChild(_t_xml_desc_node * pNode, char * pName)
{
	int i, count;
	_t_blist 		 * pQue;
	_t_xml_desc_node * pChild;
	if(pNode && pName){
		pQue = &(pNode->child);
		count = pQue->count;
		pChild = (_t_xml_desc_node *)(pQue->head);
		for(i=0; i<count; i++, pChild = (_t_xml_desc_node*)(pChild->node.next)){
			if(SYS_STRCMP(pChild->name, pName) == 0){
				return pChild;
			}
		}
	}

	return NULL;
}

static 	_t_xml_desc_node * 	_SXml2_DescNode_Show(_t_xml_desc_node * pNode, int depth)
{
	int i, j, count;
	_t_blist 		 * pQue;
	_t_xml_attr_node * pAttr;
	_t_xml_desc_node * pChild;

	if(pNode){
		/* Show the Attr */
		pQue = &(pNode->attr);
		count = pQue->count;
		pAttr = (_t_xml_attr_node *)(pQue->head);

		for(j=0; j<depth; j++){
			printf("\t");
		}
		printf("Attribute:\n");		
		for(i=0; i<count; i++, pAttr = (_t_xml_attr_node *)(pAttr->node.next)){
			for(j=0; j<depth; j++){
				printf("\t");
			}
			printf("%s\n", pAttr->name);
		}

		/* Show the Child */
		pQue = &(pNode->child);
		count = pQue->count;
		pChild = (_t_xml_desc_node *)(pQue->head);
		for(i=0; i<count; i++, pChild = (_t_xml_desc_node*)(pChild->node.next)){
			for(j=0; j<depth; j++){
				printf("\t");
			}
			printf("Child:%s  -> Depth:%d\n", pChild->name, pChild->depth);
			_SXml2_DescNode_Show(pChild, depth+1);
		}
	}

	return NULL;
}

static 	int 	_SXml2Reader_Gen_Element(xmlTextReader * pReader, _t_xml_desc_node  ** pStack){
	int i, count, depth;

	xmlChar 	* 	value;
	xmlNode 	* 	node;
	xmlAttr 	*	cur;
	
	_t_xml_desc_node * pParent;
	_t_xml_desc_node * pChild;
	_t_xml_attr_node * pAttr;

	depth 	= xmlTextReaderDepth(pReader);
	value	= xmlTextReaderLocalName(pReader);

	pParent 			= pStack[depth];
	pStack[depth + 1]	= NULL;
	/* Check the Node */
	if(value && pParent){
		pChild = _SXml2_DescNode_FindChild(pParent, (char *)value);
		if(!pChild){
			pChild = _SXml2_DescNode_Alloc((char *)value);
			if(pChild){
				BLST_ADD2T(&(pParent->child), &(pChild->node));
			}
		}

		if(pChild){
			count 	= xmlTextReaderAttributeCount(pReader);
			node 	= xmlTextReaderCurrentNode(pReader);
			cur  	= node->properties;
			for(i=0; i<count; i++, cur = cur->next){
				if(cur == NULL){
					break;
				}
				printf("Attr[%02d]: %s\n", i, cur->name);
				pAttr = _SXml2_DescNode_FindAttr(pChild, (char *)(cur->name));
				if(!pAttr){
					pAttr = _SXml2_AttrNode_Alloc((char *)(cur->name));
					if(pAttr){
						BLST_ADD2T(&(pChild->attr), &(pAttr->node));
					}
				}
			}
			pChild->depth 		= depth + 1;
			pStack[depth + 1] 	= pChild;
		}
	}

	return 0;
}

static 	void 	_SXml2Reader_Gen(xmlTextReader * pReader, _t_xml_desc_node  ** pStack) {
	int 			nodeType;
	/* Node Type & Depth */
	nodeType = xmlTextReaderNodeType(pReader);

	switch(nodeType){
		case XML_READER_TYPE_ELEMENT:
			#if 0
			SYS_TRACE(_gTraceLvl_Xml2Gen, TRACELVL_DEBUG, "Depth: %d - %d\n", depth, pStack->depth);
			#endif
			/* Tricks : POP - PUSH - POP */
			_SXml2Reader_Gen_Element(pReader, pStack);
			break;
			
		default:
			break;
	}


	return;
}


/* ---------------------------------------------------------------------------
** Xml2 Reader Re-Construct :
*/
static 	void 	_SXml2Reader_NomiStr(char * pStr){
	int i, len;
	if(pStr){
		len = SYS_STRLEN(pStr);
		for(i=0; i<len; i++){
			switch(pStr[i]){
				case '-':
					pStr[i] = '_';
					break;
				default:
					break;
			}
		}
	}
	return;
}


typedef struct{
	int 				depth;
	int 				countA;
	int 				countC;
	char 				string[_SXML_MAX_STR];
	char 				name[_SXML_MAX_STR];
	char 				attr[_SXML_MAX_ATTR][_SXML_MAX_STR];
	char 				child[_SXML_MAX_CHILD][_SXML_MAX_STR];
}_t_xml_desc_str;

typedef struct{
	int 				countD;
	_t_xml_desc_str  	desc[_SXML_MAX_DESC];
}_t_xml_desc_set;

static 	int 	_SXml2_DescGen_MergeAttr(_t_xml_desc_str * pDesc, _t_xml_desc_node * pNode)
{
	int 	i, len, flag;
	int 	j, count;
	_t_blist 		* 	pQue;
	_t_xml_attr_node* 	pAttr;
	
	char * 	pName;

	if(pDesc && pNode){
		pQue  = &(pNode->attr);
		count = pQue->count;
		pAttr = (_t_xml_attr_node *)(pQue->head);
		for(j=0; j<count;j++, pAttr=(_t_xml_attr_node *)(pAttr->node.next)){
			len = SYS_STRLEN(pAttr->name);
			flag= 0;
			
			for(i=0; i<pDesc->countA; i++){
				pName = pDesc->attr[i];
				if(SYS_STRCMP(pName, pAttr->name) == 0){
					flag = 1;
					break;
				}
			}

			if(flag == 0){
				if(pDesc->countA < _SXML_MAX_ATTR){
					pName = pDesc->attr[pDesc->countA];
					SYS_MEMCPY(pName, pAttr->name, len);
					pName[len] = 0;
					pDesc->countA += 1;
				}
			}
		}
	}
	return 0;
}

static 	int 	_SXml2_DescGen_MergeChild(_t_xml_desc_str * pDesc, _t_xml_desc_node * pNode)
{
	int 	i, len, flag;
	int 	j, count;
	_t_blist 		* 	pQue;
	_t_xml_desc_node* 	pChild;
	
	char * 	pName;
	
	if(pDesc && pNode){
		pQue  = &(pNode->child);
		count = pQue->count;
		pChild = (_t_xml_desc_node *)(pQue->head);
		for(j=0; j<count;j++, pChild=(_t_xml_desc_node *)(pChild->node.next)){
			len = SYS_STRLEN(pChild->name);
			flag= 0;
			for(i=0; i<pDesc->countC; i++){
				pName = pDesc->child[i];
				if(SYS_STRCMP(pName, pChild->name) == 0){
					flag = 1;
					break;
				}
			}

			if(flag == 0){
				printf("Add Child[%02d]: %s\n", i, pChild->name);
				if(pDesc->countC < _SXML_MAX_CHILD){
					pName = pDesc->child[pDesc->countC];
					SYS_MEMCPY(pName, pChild->name, len);
					pName[len] = 0;
					pDesc->countC += 1;
				}
			}
		}
	}
	return 0;
}

static 	int 	_SXml2_DescGen_MergeNode(_t_xml_desc_set * pSet, _t_xml_desc_node * pNode)
{
	int 	i, len, flag;
	_t_xml_desc_str * 	pDesc;
	char * 	pName;

	if(pSet && pNode && pNode->name){
		len = SYS_STRLEN(pNode->name);

		pDesc = pSet->desc;
		/* Check Desc */
		flag = 0;
		for(i=0; i<pSet->countD; i++, pDesc++){
			if(SYS_STRCMP(pDesc->name, pNode->name) == 0){
				flag = 1;
				break;
			}
		}
		
		if(flag == 0){
			if(pSet->countD < _SXML_MAX_DESC){
				printf("Add Node[%02d]: %s\n", i, pNode->name);
				/* Depth */
				pDesc = pSet->desc + pSet->countD;
				pDesc->depth = pNode->depth;

				/* Set Name & String */
				pName = pDesc->name;
				SYS_MEMCPY(pName, pNode->name, len);
				pName[len] = 0;

				pName = pDesc->string;
				SYS_MEMCPY(pName, pNode->name, len);
				pName[len] = 0;

				pSet->countD += 1;
				/* Merge */
				_SXml2_DescGen_MergeAttr(pDesc, pNode);
				_SXml2_DescGen_MergeChild(pDesc, pNode);
			}
		}
		else{
			printf("Merge Node[%02d]: %s\n", i, pNode->name);
			/* Depth */
			if(pDesc->depth < pNode->depth){
				pDesc->depth = pNode->depth;
			}
			/* Merge */
			_SXml2_DescGen_MergeAttr(pDesc, pNode);
			_SXml2_DescGen_MergeChild(pDesc, pNode);
		}
	}

	
	return 0;
}

static 	int 	_SXml2_DescGen_Scan(_t_xml_desc_set * pSet, _t_xml_desc_node * pNode)
{
	int i, count;
	_t_blist 		 * pQue;
	_t_xml_desc_node * pChild;

	/* Show the Child */
	pQue = &(pNode->child);
	count = pQue->count;
	pChild = (_t_xml_desc_node *)(pQue->head);
	for(i=0; i<count; i++, pChild = (_t_xml_desc_node*)(pChild->node.next)){
		_SXml2_DescGen_Scan(pSet, pChild);
	}

	/* Merge the Attribute */
	_SXml2_DescGen_MergeNode(pSet, pNode);

	return 0;
}

static 	void 	_SXml2_DescGen_Show(_t_xml_desc_set * pSet)
{
	int i, j, count;
	_t_xml_desc_str	*	pI;
	
	count 	= pSet->countD;
	pI 		= pSet->desc;
	for(i=0; i<count; i++, pI++){
		printf("\n%s <-> Depth:%d\n", pI->name, pI->depth);

		/* Attr */
		printf("Attr:%d\n", pI->countA);
		for(j=0; j<pI->countA; j++){
			printf("%s\n", pI->attr[j]);
		}
		/* Child */
		printf("Child:%d\n", pI->countC);
		for(j=0; j<pI->countC; j++){
			printf("%s\n", pI->child[j]);
		}
	}
	return;
}


/* ---------------------------------------------------------------------------
** Xml2 Reader Gen C-Code :
*/
static 	void 	_SXml2_CodeGen_Indent(FILE * hFile, int n){
	int i;
	for(i=0; i<n; i++){
		SYS_FPRINTF(hFile, "\t");
	}
	return;
}


static 	void 	_SXml2_CodeGen_Attr(FILE * hFile, _t_xml_desc_str * pDesc){
	int i;

	SYS_FPRINTF(hFile, "\n");
	/* Comments */
	SYS_FPRINTF(hFile, "/* Attribute for: %s */\n", pDesc->name);
	SYS_FPRINTF(hFile, "static 	char* 		_gA_%s[] = {\n", pDesc->string);
	for(i=0; i<pDesc->countA; i++){
		_SXml2_CodeGen_Indent(hFile, 1);
		SYS_FPRINTF(hFile, "\"%s\",\n", pDesc->attr[i]);	
	};
	_SXml2_CodeGen_Indent(hFile, 1);
	SYS_FPRINTF(hFile, "NULL\n};\n");	
	return;
}

static 	void 	_SXml2_CodeGen_Child(FILE * hFile, _t_xml_desc_str * pDesc){
	int i;

	SYS_FPRINTF(hFile, "\n");
	/* Comments */
	SYS_FPRINTF(hFile, "/* Children for: %s */\n", pDesc->name);
	SYS_FPRINTF(hFile, "static 	_t_xml_desc* 	_gC_%s[] = {\n", pDesc->string);
	for(i=0; i<pDesc->countC; i++){
		_SXml2_CodeGen_Indent(hFile,1);
		SYS_FPRINTF(hFile, "&_gD_%s,\n", pDesc->child[i]);	
	};
	_SXml2_CodeGen_Indent(hFile, 1);
	SYS_FPRINTF(hFile, "NULL\n};\n");	
	return;
}

static 	void 	_SXml2_CodeGen_CbSetChild(FILE * hFile, _t_xml_desc_str * pDesc){
	int 	i, count;
	SYS_FPRINTF(hFile, "\n");

	count = pDesc->countC;
	/* Comments */
	SYS_FPRINTF(hFile, "/* CallBack Function for Set Children of: %s */\n", pDesc->name);
	SYS_FPRINTF(hFile, "static 	void *	_cbSetChild_%s(void * pCookie, unsigned char * pName, int id){\n", pDesc->string);
	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "/* User's Code: Transform the pCookie to Real Data Struct.  */\n\n");

	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "switch(id){\n");

	if(count > 0){
		for(i=0; i<count; i++){
			_SXml2_CodeGen_Indent(hFile,2);
			SYS_FPRINTF(hFile, "case (%-3d):\n", i);
				_SXml2_CodeGen_Indent(hFile,3);
				SYS_FPRINTF(hFile, "/* User's Code For Child: %s  */\n\n", pDesc->child[i]);
				_SXml2_CodeGen_Indent(hFile,3);
				SYS_FPRINTF(hFile, "break;\n");
				SYS_FPRINTF(hFile, "\n");
		}
	}
	else{
		_SXml2_CodeGen_Indent(hFile,2);
		SYS_FPRINTF(hFile, "/* User's Code Here: */\n\n");
	}

		_SXml2_CodeGen_Indent(hFile,2);
		SYS_FPRINTF(hFile, "default:\n");
			_SXml2_CodeGen_Indent(hFile,3);
			SYS_FPRINTF(hFile, "break;\n");
			SYS_FPRINTF(hFile, "\n");

	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "}\n");
			
	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "return pCookie;\n");

	SYS_FPRINTF(hFile, "}\n");	
	return;
}


static 	void 	_SXml2_CodeGen_CbSetAttr(FILE * hFile, _t_xml_desc_str * pDesc){
	int 	i, count;
	SYS_FPRINTF(hFile, "\n");

	count = pDesc->countA;
	/* Comments */
	SYS_FPRINTF(hFile, "/* CallBack Function for Set Attribute of: %s */\n", pDesc->name);
	SYS_FPRINTF(hFile, "static 	void *	_cbSetAttr_%s(void * pCookie, unsigned char * pName, int id, unsigned char * pValue){\n", pDesc->string);

	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "/* User's Code: Transform the pCookie to Real Data Struct.  */\n\n");

	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "switch(id){\n");

	if(count > 0){
		for(i=0; i<count; i++){
			_SXml2_CodeGen_Indent(hFile,2);
			SYS_FPRINTF(hFile, "case (%-3d):\n", i);
				_SXml2_CodeGen_Indent(hFile,3);
				SYS_FPRINTF(hFile, "/* User's Code For Attr: %s  */\n\n", pDesc->attr[i]);
				_SXml2_CodeGen_Indent(hFile,3);
				SYS_FPRINTF(hFile, "break;\n");
				SYS_FPRINTF(hFile, "\n");
		}

	}
	else{
		_SXml2_CodeGen_Indent(hFile,2);
		SYS_FPRINTF(hFile, "/* User's Code Here: */\n\n");
	}
		_SXml2_CodeGen_Indent(hFile,2);
		SYS_FPRINTF(hFile, "default:\n");
			_SXml2_CodeGen_Indent(hFile,3);
			SYS_FPRINTF(hFile, "break;\n");
			SYS_FPRINTF(hFile, "\n");

	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "}\n");
			
	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "return pCookie;\n");

	SYS_FPRINTF(hFile, "}\n");	
	return;
}


static 	void 	_SXml2_CodeGen_Desc(FILE * hFile, _t_xml_desc_str * pDesc){
	SYS_FPRINTF(hFile, "\n");
	/* Comments */
	SYS_FPRINTF(hFile, "/* Description: %s */\n", pDesc->name);
	SYS_FPRINTF(hFile, "static 	_t_xml_desc	 _gD_%s = {\n", pDesc->string);

	/* The Name */
	_SXml2_CodeGen_Indent(hFile, 1);
	SYS_FPRINTF(hFile, "/* Name */\n");

	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "\"%s\",\n\n", pDesc->name);

	/* The Attribute */
	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "/* Attribute */\n");
	
	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "{%d,\t _gA_%s},\n\n", pDesc->countA, pDesc->string);

	/* The Children */
	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "/* Children */\n");

	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "{%d,\t _gC_%s},\n\n", pDesc->countC, pDesc->string);

	/* The CallBack */
	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "/* Callback */\n");
	
	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "(void* 	(*)())_cbSetChild_%s,\n", pDesc->string);
	_SXml2_CodeGen_Indent(hFile,1);
	SYS_FPRINTF(hFile, "(void* 	(*)())_cbSetAttr_%s,\n", pDesc->string);
	

	SYS_FPRINTF(hFile, "};\n");	
	
	return;
}


static 	void 	_SXml2_CodeGen_Entry(FILE * hFile, _t_xml_desc_str * pDesc){
	SYS_FPRINTF(hFile, "\n\n");
	/* Comments */
	SYS_FPRINTF(hFile, "/* Entry: %s */\n", pDesc->name);
	SYS_FPRINTF(hFile, "int 	Xml2Parse_%s(const char * hFile, void * pCookie){\n", pDesc->string);

	/* Variables */
	_SXml2_CodeGen_Indent(hFile, 1);
	SYS_FPRINTF(hFile, "/* Variables */\n");

	_SXml2_CodeGen_Indent(hFile, 1);
	SYS_FPRINTF(hFile, "_t_xml_stack_frame 	frame[_SXML_STACK_MAX_FRAME];\n");

	_SXml2_CodeGen_Indent(hFile, 1);
	SYS_FPRINTF(hFile, "_t_xml_stack	 	stack;\n\n");

	/* Parse */
	_SXml2_CodeGen_Indent(hFile, 1);
	SYS_FPRINTF(hFile, "_SXML_STACK_INIT(&stack, frame, _SXML_STACK_MAX_FRAME, &_gD_%s, NULL);\n", 
		pDesc->string);

	_SXml2_CodeGen_Indent(hFile, 1);
	SYS_FPRINTF(hFile, "_SXML_FRAME_SET_PARENT(&(frame[1]), &_gD_%s);\n", 		
		pDesc->string);

	_SXml2_CodeGen_Indent(hFile, 1);
	SYS_FPRINTF(hFile, "_SXML_FRAME_SET_COOKIE(&(frame[1]), pCookie);\n\n");

	_SXml2_CodeGen_Indent(hFile, 1);
	SYS_FPRINTF(hFile, "return SXml2Reader_Parse(hFile, &stack);\n");
	
	SYS_FPRINTF(hFile, "}\n");

	return;
}


/* ---------------------------------------------------------------------------
** Xml2 Reader Construct With Gen C-Code :
*/
static 	void 	_SXml2_CodeGen_Header(const char * hName, _t_xml_desc_str * pEntry)
{
	FILE 			* hGen;
	char 			  nGen[S_APP_MAX_PATH + 1];

	if(pEntry){
		/* Generate the Source */
		SYS_SNPRINTF(nGen, S_APP_MAX_PATH, "genx_%s.h", hName);
		hGen = fopen(nGen, "w+");
		SYS_FPRINTF(hGen, "/* This File is Generated by the Femto's XML2-Gen.*/\n");
		SYS_FPRINTF(hGen, "#ifndef _INC_XML2PARSE_%s\n", pEntry->string);
		SYS_FPRINTF(hGen, "#define _INC_XML2PARSE_%s\n\n", pEntry->string);

		SYS_FPRINTF(hGen, "#include \"ak_types.h\"\n");
		SYS_FPRINTF(hGen, "#include \"ak_xml2.h\"\n\n");

		SYS_FPRINTF(hGen, "#ifdef __cplusplus\n");
		SYS_FPRINTF(hGen, "\textern \"C\" {\n");
		SYS_FPRINTF(hGen, "#endif\n\n");

		SYS_FPRINTF(hGen, "/* Entry: %s */\n", pEntry->name);
		SYS_FPRINTF(hGen, "extern	int 	Xml2Parse_%s(const char * hFile, void * pCookie);\n\n", pEntry->string);

		SYS_FPRINTF(hGen, "#ifdef __cplusplus\n");
		SYS_FPRINTF(hGen, "\t}\n");
		SYS_FPRINTF(hGen, "#endif\n\n");
		SYS_FPRINTF(hGen, "#endif\n\n");
		fclose(hGen);
	}

	return;
}

static 	void 	_SXml2_CodeGen_Source(const char * hName, _t_xml_desc_str * pEntry, _t_xml_desc_set * pSet)
{
	int 	i, count;
	_t_xml_desc_str	* pI;
	FILE 			* hGen;
	char 			  nGen[S_APP_MAX_PATH + 1];

	if(pEntry){
		/* Generate the Source */
		SYS_SNPRINTF(nGen, S_APP_MAX_PATH, "genx_%s.c", hName);
		hGen = fopen(nGen, "w+");
		SYS_FPRINTF(hGen, "/* This File is Generated by the Femto's XML2-Gen.*/\n");
		SYS_FPRINTF(hGen, "#include \"genx_%s.h\"\n\n", hName);
		
		count = pSet->countD;
		pI = pSet->desc;
		for(i=0; i<count; i++, pI++){
			if(SYS_STRCMP(pI->name, "Root") != 0){
				_SXml2_CodeGen_Attr(hGen, pI);
				_SXml2_CodeGen_Child(hGen, pI);
				_SXml2_CodeGen_CbSetChild(hGen, pI);
				_SXml2_CodeGen_CbSetAttr(hGen, pI);
				_SXml2_CodeGen_Desc(hGen, pI);
			}
		}
		_SXml2_CodeGen_Entry(hGen, pEntry);
		fclose(hGen);
	}
	
}

static 	void 	_SXml2_DescGen_ReConstruct(_t_xml_desc_node * pRoot, const char * hName, _t_xml_desc_set * pSet)
{
	int 	i, j, k, count;
	_t_xml_desc_str	*	pEntry;
	_t_xml_desc_str	*	pI;
	_t_xml_desc_str	*	pJ;
	_t_xml_desc_str 	temp;

	
	SYS_MEMZERO(pSet, sizeof(_t_xml_desc_set));
	_SXml2_DescGen_Scan(pSet, pRoot);
	
	/* Re-Order */
	count = pSet->countD;
	pI = pSet->desc;
	for(i=0; i<count; i++, pI++){
		pJ = pSet->desc + i;
		for(j=i; j<count; j++, pJ++){
			/* Check the Depth */
			if(pI->depth < pJ->depth){
				temp = *pI;
				*pI = *pJ;
				*pJ = temp;
			}
			/* Check the Child */
			else{
				for(k=0; k<pI->countC; k++){
					if(SYS_STRCMP(pI->child[k], pJ->name) == 0){
						temp = *pI;
						*pI = *pJ;
						*pJ = temp;
						break;
					}
				}
			}
		}
	}

	/* Nomi */
	pI = pSet->desc;
	for(i=0; i<count; i++, pI++){
		_SXml2Reader_NomiStr(pI->string); 
		for(j=0; j<pI->countC; j++){
			_SXml2Reader_NomiStr(pI->child[j]);
		}
	}


	_SXml2_DescGen_Show(pSet);

	
	/* Check if Depth = 1 Only Has 1, That is a Fake Root */
	j = 0;
	pEntry 	= NULL;
	pI 		= pSet->desc;
	for(i=0; i<count; i++, pI++){
		if(pI->depth == 1){
			pEntry = pI;
			j += 1;
		}
	}

	if(j == 1){
		_SXml2_CodeGen_Header(hName, pEntry);
		_SXml2_CodeGen_Source(hName, pEntry, pSet);
	}
	else{
		printf("Depth = 1 (%d) Struct. Please Use the Unique 1st Level Desc.\n", j);
	}
	
	return;
}


static 	int 	SXml2Reader_Gen(const char * hFile, const char * hName, _t_xml_desc_node** stack, _t_xml_desc_set * pSet) 
{
    int 			ret = -1;
    xmlTextReader 	* pReader;
	_t_xml_desc_node* pRoot;
	
    pReader = xmlNewTextReaderFilename(hFile);
    if (pReader != NULL) {
		
		pRoot = _SXml2_DescNode_Alloc("Root");
		if(pRoot){
			stack[0] = pRoot;
	        ret = xmlTextReaderRead(pReader);
	        while (ret == 1) {
	            _SXml2Reader_Gen(pReader, stack);
	            ret = xmlTextReaderRead(pReader);
	        }
		}

		_SXml2_DescNode_Show(pRoot, 0);
		_SXml2_DescGen_ReConstruct(pRoot, hName, pSet);


		/* Free */
		_SXml2_DescNode_Free(pRoot);
        xmlFreeTextReader(pReader);
        if (ret != 0) {
            SYS_TRACE(_gTraceLvl_Xml2Gen, TRACELVL_WARNING, "%s : Parse Fail\n", hFile);
        }
    } 
	else {
		SYS_TRACE(_gTraceLvl_Xml2Gen, TRACELVL_ERROR, "%s : Open Fail\n", hFile);
    }

	return ret;
}


static 	_t_xml_desc_node*  	_g_xml_desc_stack[_SXML_STACK_MAX_FRAME];
static 	_t_xml_desc_set 	_g_xml_desc_set;

int		main(int   argc, char   *argv[])
{
	int 	len;
	char * 	prefix;
	char 	sFile[S_APP_MAX_PATH + 1];

	if(argc < 2){
		printf("Usage:ak_genx ???.xml\n");
		return -1;
	}
	len = -1;
	if(argv[1]){
		len 	= SYS_STRLEN(argv[1]);
		if((len > 0) && (len <= S_APP_MAX_PATH)) {
			SYS_MEMCPY(sFile, argv[1],len);
			sFile[len] = 0;
			prefix	= SYS_STRSTR(sFile, ".xml");
			if(prefix){
				*prefix = '\0';
				len  = SXml2Reader_Gen((const char *)argv[1], (const char *)sFile, _g_xml_desc_stack, &_g_xml_desc_set);
			}
		}
	}
	return len;
}

